home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Interactive Web Graphics with Shout 3D
/
Interactive Web Graphics With Shout 3D.iso
/
mac
/
Shout3Ddemo
/
S3D_2E1.exe
/
Shout3d_runtime
/
codebase
/
applets
/
MultiTestPanel.java
< prev
next >
Wrap
Text File
|
2000-10-10
|
13KB
|
388 lines
/**
Company: Eyematic Interfaces
Project: Shout3D 2.0 Sample Code
Class: MultiTestPanel
Date: April 26, 1999
Description: Tests various features. Press '?' for Java Panel instructions
(C) Copyright Eyematic Interfaces, Inc. - 1997-2000 - All rights reserved
*/
package applets;
import java.applet.*;
import java.awt.*;
import java.awt.image.*;
import java.io.*;
import java.util.Date;
import java.util.Vector;
import java.net.URL;
import shout3d.*;
import shout3d.math.*;
import shout3d.core.*;
/**
*
* Panel that tests lots of features, including
* little markers that show the location and normal of geometry
* below the mouse.
*
* Press '?' to see instructions in the Java Panel.
*
* @author Paul Isaacs
* @author Jim Stewartson
* @author Dave Westwood
*/
public class MultiTestPanel extends Shout3DPanel implements DeviceObserver {
boolean locationTracking = false;
boolean normalTracking = false;
int curMouseX, curMouseY;
boolean mouseMoved = false;
/**
* Constructor
*/
public MultiTestPanel(Shout3DApplet applet){
super(applet);
}
public void customInitialize(){
// Register to watch rendering, the keyboard and mouse
addDeviceObserver(this,"KeyboardInput", null);
addDeviceObserver(this,"MouseInput", null);
getRenderer().addRenderObserver(this,null);
String normalTrackingString = applet.getParameter("normalTracking");
if (normalTrackingString != null && normalTrackingString.equals("true"))
normalTracking = true;
else
normalTracking = false;
String locationTrackingString = applet.getParameter("locationTracking");
if (locationTrackingString != null && locationTrackingString.equals("true"))
locationTracking = true;
else
locationTracking = false;
}
/**
* Clean up by unregistering observers
*/
protected void finalize() throws Throwable {
getRenderer().removeRenderObserver(this);
removeDeviceObserver(this,"KeyboardInput");
removeDeviceObserver(this,"MouseInput");
super.finalize();
}
/**
* Override to do a pick and show results, if desired.
* Tracking of the pick must be performed during onPostRender.
* This is because multithreading may put rendering in a separate thread,
* but trackPick() adds/removes children.
* Hence, unless we insure that trackPick() occurs between renders,
* the children could disappear during the middle
* of a render, which can cause null pointer exceptions.
*
* Note that no onPreRender() method is implemented in this class,
* even though it is required for all classes implementing RenderObserver.
* This is because the super class implements RenderObserver fully
* and onPreRender is inherited.
* Hence this class needs only to override the onPostRender() method,
* making sure to call super.onPostRender(r,userData) within the body
* of the method.
*/
public void onPostRender(Renderer r, Object userData) {
super.onPostRender(r,userData);
if (mouseMoved && (locationTracking || normalTracking))
trackPick();
}
//{{ DeviceObserver methods
/**
* Processes mouse and keyboard input.
*
* Moving the mouse records the mouse location for later use during
* trackPick(), which is called between renders (see onPostRender above)
*
* Pressing keyboard keys performs any of a series of tests.
*
*/
public boolean onDeviceInput(DeviceInput di, Object userData) {
if (di instanceof MouseInput){
if (((MouseInput)di).which == MouseInput.MOVE) {
curMouseX = ((MouseInput)di).x;
curMouseY = ((MouseInput)di).y;
// Do not do the pick right here. Set this flag so it will
// occur during onPostRender. See onPostRender for why.
mouseMoved = true;
}
}
else {
KeyboardInput ki = (KeyboardInput) di;
if (ki.which == KeyboardInput.PRESS) {
switch(ki.key) {
case 'w': case 'W':
// W key pressed. Write the scene to a little text frame
// (WriterTextFrame is defined in this file.
if (getScene() != null) {
WriterTextFrame myFrame = new WriterTextFrame();
myFrame.resize(400, 600);
myFrame.show();
ByteArrayOutputStream os = new ByteArrayOutputStream();
PrintStream ps = new PrintStream(os);
Shout3DWriter writer = new Shout3DWriter();
writer.write(getScene(),ps);
myFrame.getTextArea().setText(os.toString());
}
return true;
case 'n': case 'N':
// N key pressed. Toggle normal-tracking. Each time the mouse moves, do a
// pick and place arrow at picked location, pointing in direction of normal
// info to the console.
normalTracking = !normalTracking;
if (!normalTracking)
hideNormalMarker();
break;
case 'l': case 'L':
// L key pressed. Toggle location tracking. Each time the mouse moves, do a pick
// and place nubbin at picked location.
locationTracking = !locationTracking;
if (!locationTracking)
hidePositionMarker();
break;
case '1':
// prints paths to all IndexedFaceSet nodes.
searchAndPrint("IndexedFaceSet");
break;
case '2':
// prints paths to all TimeSensor nodes.
searchAndPrint("TimeSensor");
break;
case '3':
// prints paths to all Group nodes.
searchAndPrint("Group");
break;
case '4':
// prints paths to all nodes.
searchAndPrint("Node");
break;
case '5':
// prints paths to all nodes.
searchAndPrint("Switch");
break;
case '?':
// Print help message.
System.out.println("-----------------------------------");
System.out.println("KEY: ACTION:");
System.out.println("n NORMAL picking toggle. Turns tracking of surface normal on/off");
System.out.println("l LOCATION picking toggle. Turns tracking of picked location on/off");
System.out.println("w WRITE scene to textArea in VRML-like syntax");
System.out.println("1 #1--diagnostic - search for IndexedFaceSets");
System.out.println(" and print paths to them");
System.out.println("2 #2--diagnostic - search for TimeSensors");
System.out.println(" and print paths to them");
System.out.println("3 #3--diagnostic - search for Groups");
System.out.println(" and print paths to them");
System.out.println("4 #4--diagnostic - search for all Nodes");
System.out.println(" and print paths to them");
}
}
}
return false;
}
//}} DeviceObserver methods
/**
* Searches for paths to all nodes of the given type, printing the results
* to the console.
*/
void searchAndPrint(String typeName) {
System.out.println("RESULTS OF SEARCH FOR ALL " + typeName + "s :");
Searcher s = getNewSearcher();
s.setType(typeName);
Node[][] paths = s.searchAll(getScene());
if (paths == null || paths.length == 0) {
System.out.println("No paths found");
return;
}
System.out.println("Number of paths is " + paths.length);
for (int i = 0; i < paths.length; i++) {
Node[] p = paths[i];
System.out.println("PATH " + i);
for (int j = 0; j < p.length; j++) {
if (p[j] == null)
System.out.println(" node " + j + " is null");
else {
String name = p[j].getDEFName();
if (name == null)
name = "";
System.out.println(" node " + j + " name:" + name + " type " + p[j].getTypeName());
}
}
}
System.out.println("-------------------------------------------");
}
Picker myPicker;
private Node[] pickPath;
/**
* Tracks the current cursor location with a nubbin or an arrow.
*
* If normalTracking, then an arrow will be stuck at the picked
* location, pointing in the direction of the pick-point-normal.
*
* If locationTracking, then a nubbin will be placed at the picked location.
*/
void trackPick() {
if (myPicker == null)
myPicker = getNewPicker();
myPicker.setPickInfo(Picker.POINT, (normalTracking || locationTracking));//Only needed for these two
myPicker.setPickInfo(Picker.NORMAL, normalTracking);//Only if normalTracking
// Hide the markers, so that the markers can't be picked.
hideNormalMarker();
hidePositionMarker();
pickPath = myPicker.pickClosest(curMouseX, curMouseY);
float[] pickedPoint = myPicker.getPickInfo(Picker.POINT);//Garbage if (!normalTracking&&!locationTracking)
float[] pickedNormal = myPicker.getPickInfo(Picker.NORMAL);//Garbage if !normalTracking
if (pickPath != null){
if (locationTracking)
showPositionMarker(pickedPoint);
if (normalTracking)
showNormalMarker(pickedPoint, pickedNormal);
}
mouseMoved = false;
}
// These store references to the markers
Transform positionMarker, normalMarker;
// These are cached to easily call addChidren/removeChildren
Node[] positionMarkerKidArray;
Node[] normalMarkerKidArray;
// Scale applied to the marker,
// can be set with the markerScale parameter in the html file.
float[] markerScale = { .1f, .1f, .1f};
/**
* Hides the normal marker by removing from the scene.
*/
void hideNormalMarker(){
if (normalMarker != null) {
getScene().removeChildren(normalMarkerKidArray);
}
}
/**
* Hides the position marker by removing from the scene.
*/
void hidePositionMarker(){
if (positionMarker != null){
getScene().removeChildren(positionMarkerKidArray);
}
}
/**
* Shows the normal marker and places according to input parameters.
*/
void showNormalMarker(float[/*3*/]position, float[/*3*/] direction){
if (normalMarker == null){
initMarkerGeoms();
}
normalMarker.translation.setValue(position);
//Set rotation to point the y axis towards the direction. Axis is cross product, angle is acos(dotProduct)
// Axis is cross product yAxis.cross(direction), which is (dz, 0, -dx)
normalMarker.rotation.getValue()[0] = direction[2];
normalMarker.rotation.getValue()[1] = 0;
normalMarker.rotation.getValue()[2] = -direction[0];
MatUtil.normalize(normalMarker.rotation.getValue()); // will just normalize 1st 3 of 4 components
normalMarker.rotation.getValue()[3] = (float) Math.acos(direction[1]); // angle whose cosine is dotprod of (0,1,0) and direction
normalMarker.rotation.setValue(normalMarker.rotation.getValue());
getScene().addChildren(normalMarkerKidArray);
}
/**
* Shows the position marker and places according to input parameters.
*/
void showPositionMarker(float[/*3*/]position){
if (positionMarker == null){
initMarkerGeoms();
}
positionMarker.translation.setValue(position);
getScene().addChildren(positionMarkerKidArray);
}
/**
* Reads the file given by the parameter "markerGeometry"
* and searches inside for two named nodes:
* "PositionMarker" and "NormalMarker"
*
* Saves these and also scales them by markerScale (which
* may be set as an html input parameter)
*/
void initMarkerGeoms(){
Transform markerRoot = new Transform();
String markerGeomString = applet.getParameter("markerGeometry");
if (markerGeomString == null){
System.out.println("Error -- Mo markerGeometry parameter specified for applet");
System.out.println(" Can not show picked location");
return;
}
String[] urlArray = { markerGeomString };
// Don't load in a separate thread:
boolean wasSeparate = isLoadResourcesInSeparateThread();
setLoadResourcesInSeparateThread(false);
loadURL(urlArray, markerRoot);
setLoadResourcesInSeparateThread(wasSeparate);
if (markerRoot == null) {
throw new Shout3DException("ERROR - could not load marker geometry");
}
Searcher mySearcher = getNewSearcher();
// initialize positionMarker
mySearcher.setDefName("PositionMarker");
Node[] sResult = mySearcher.searchFirst(markerRoot);
if (sResult==null){
throw new Shout3DException("ERROR - could not find PositionMarker");
}
positionMarker = (Transform) sResult[sResult.length-1];
// Create the array used to add the positionMarker to the scene.
positionMarkerKidArray = new Node[1];
positionMarkerKidArray[0] = positionMarker;
// initialize normalMarker
mySearcher.setDefName("NormalMarker");
sResult = mySearcher.searchFirst(markerRoot);
if (sResult==null){
throw new Shout3DException("ERROR - could not find NormalMarker");
}
normalMarker = (Transform) sResult[sResult.length-1];
// Create the array used to add the normalMarker to the scene.
normalMarkerKidArray = new Node[1];
normalMarkerKidArray[0] = normalMarker;
String markerScaleParamString = applet.getParameter("markerScale");
if (markerScaleParamString != null){
markerScale[0] = markerScale[1] = markerScale[2] = Float.valueOf(markerScaleParamString).floatValue();
}
positionMarker.scale.setValue(markerScale);
normalMarker.scale.setValue(markerScale);
}
}
/**
* A little class that puts a text area in its own
* free floating frame.
*/
class WriterTextFrame extends Frame {
TextArea myTextArea;
WriterTextFrame() {
setLayout(new BorderLayout());
myTextArea = new TextArea();
this.add("Center",myTextArea);
}
TextArea getTextArea() { return myTextArea; }
}